home *** CD-ROM | disk | FTP | other *** search
- #include "loadpcx.h"
- #include <stdio.h> /* for FILE functions */
- #include <mem.h> /* for memcpy,memset */
- #include <malloc.h> /* for farmalloc,farfree */
-
- /* Simple macros used to dynamically allocate/free memory */
- /* NOTE that they are only used to allocate a file buffer */
- /* all other allocations are explicit far allocations */
-
- #define CREATE_BLOCK(size) malloc(size)
- #define FREE_BLOCK(ptr) free(ptr)
-
- /* Header of a PCX file */
-
- int ErrorCode;
-
-
- struct PcxHeader
- {
- byte manufacturer; /* 0x0a --signifies a PCX file */
-
- byte version; /* version 5 is what we look for */
-
- byte encoding; /* when 1,it's RLE encoding (only type as of yet) */
-
- byte bitsperpixel; /* how many bits to represent 1 pixel */
-
- word xmin, ymin, xmax, ymax; /* dimensions of window */
-
- word HDPI, VDPI; /* device resolution (horizontal,vertical) */
-
- struct VgaPalette colormap[16]; /* 16-color palette */
-
- byte reserved;
-
- byte nplanes; /* number of color planes */
-
- word bytesperline; /* number of bytes per line (per color plane) */
-
- word palette_info; /* 1 = color,2 = grayscale (unused in v.5+) */
-
- word swidth,sheight; /* width and height of screen */
-
- byte filler[54]; /* used to fill-out 128 byte header (useless) */
- };
-
- /* We keep a static copy of PcxHeader to work with */
-
- static struct PcxHeader head;
-
- /*------------------------------------------------------------------------*/
- /* */
- /* pcx_decode_line(FILE *,byte *bufp,word bpline); */
- /* */
- /* This function modified from: */
- /* */
- /* 'The C Users Journal' magazine, August 1991 issue */
- /* Article 'PCX Graphics' by Ian Ashdown */
- /* */
- /* Decode one line of EGA or VGA PCX file. */
- /* Returns FALSE only if a file error was encountered. */
- /* */
- /*------------------------------------------------------------------------*/
-
- static bool near pcx_decode_line(FILE * fp,byte *bufp,word bpline)
- {
- int data; /* data byte retrieved from file */
- int count; /* repeat count */
- int offset; /* buffer offset */
-
- offset = 0;
-
- while (offset < bpline)
- {
- /* Important to check for EOF here, so that we do not overrun */
- /* buffer (if not checked, it will judge EOF to be a 63 repeat count */
-
- if ((data = getc(fp)) == EOF)
- return FALSE;
-
- /* If upper 2 bits are set, it's a count byte */
-
- if ((data & 0xc0) == 0xc0)
- {
- count = data & 0x3f; /* mask off repeat count */
-
- if ((data = getc(fp)) == EOF) /* get data to repeat */
- return FALSE;
-
- _fmemset(bufp,data,count); /* duplicate byte */
- bufp += count;
- offset += count;
- }
- else
- {
- *bufp++ = (byte) data;
- offset++;
- }
- }
- return TRUE;
- }
-
- /*------------------------------------------------------------------------*/
- /* */
- /* valid_pcx(FILE * fp); */
- /* */
- /* Check the header and the file to see if it's a valid 256-color file */
- /* struct PcxHeader 'head' must be set prior to calling this function. */
- /* */
- /*------------------------------------------------------------------------*/
-
- bool valid_pcx(FILE * fp)
- {
- long curpos;
- int palsig;
-
- /* If not a PCX file, or unknown type, return invalid */
-
- if (head.manufacturer != 0x0a || head.version != 5 ||
- head.encoding != 1)
- {
- ErrorCode = 4;
- return FALSE;
- }
-
- /* If it's not a 256-color PCX file, return invalid */
-
- if (head.nplanes != 1 || head.bitsperpixel != 8)
- {
- ErrorCode = 1;
- return FALSE;
- }
- /*
- * Read the 769th byte from the end of the file to see if it contains
- * the 'palette signature', being sure to restore file position after
- */
- curpos = ftell(fp);
-
- fseek(fp,-769,SEEK_END);
-
- palsig = fgetc(fp);
-
- fseek(fp,curpos,SEEK_SET);
-
- if (palsig != 0xc) /* palette signature? */
- {
- ErrorCode = 2;
- return FALSE; /* nope, bad PCX file */
- }
-
- return TRUE;
- }
-
-
- /*------------------------------------------------------------------------*/
- /* */
- /* int load_pcx(char * name,PcxPix * pix,VgaPalette * pal); */
- /* */
- /* Decode a pcx file, place the image (and size info) into 'pix', */
- /* and place the 256-color palette into 'pal' */
- /* */
- /* NOTE: Rarely, a PCX file is saved with extra padding appended to */
- /* each scan line. When it is done, it's only to make each scan line */
- /* have an even number of bytes. This function (and most others) just */
- /* loads these 'pad' bytes as part of the image. In most (if not all) */
- /* cases, a PCX file is saved as a whole video page (in which no padding */
- /* would be needed), so this isn't much of a concern. */
- /*------------------------------------------------------------------------*/
-
- int load_pcx(const char *name,struct PcxPix *pix,struct VgaPalette *pal)
- {
- FILE * fp; /* FILE, and */
- char * fbuf; /* it's buffer */
-
- word width,height,theight;
- long piclen;
- byte *pcx_image;
- byte *dest;
- byte *tpal;
-
- /* Open the file in read-only binary mode */
-
- fp = fopen(name,"rb");
- if (fp == NULL)
- {
- ErrorCode = -1;
- return pcx_openerr;
- }
-
- /* Read in the header */
-
- if (fread(&head,sizeof(struct PcxHeader),1,fp) != 1)
- {
- ErrorCode = -2;
- fclose(fp);
- return pcx_ferror;
- }
-
- /* Ensure that the pcx file is valid */
-
- if (!valid_pcx(fp))
- {
- fclose(fp);
- return pcx_invalid;
- }
- /* Calculate the width and height of image (see notes above on width) */
- /* Bytes-per-line is used, since it includes padding count */
-
- width = head.bytesperline;
- height = head.ymax - head.ymin + 1;
-
- piclen = width * height;
- if (piclen > 64000L)
- {
- fclose(fp);
- ErrorCode = -5;
- return(pcx_invalid);
- }
-
- /* Now allocate space to save the image in */
-
- pcx_image = malloc(piclen);
-
- /* Allocate a buffer for use with the FILE structure */
-
- fbuf = CREATE_BLOCK(BUFSIZ);
-
- /* If any allocations failed, return with an out-of-memory error */
-
- if (fbuf == NULL || pcx_image == NULL)
- {
- if (fbuf == NULL)
- printf("fbuf failed\n");
-
- if (pcx_image == NULL)
- {
- printf("pcx_image failed\n");
- printf("WT:%d HT:%d\n",width,height);
- }
- ErrorCode = -4;
- fclose(fp);
-
- /* If any allocations _did_ work, be sure to free them up before leaving */
- if (fbuf != NULL)
- FREE_BLOCK(fbuf);
- if (pcx_image != NULL)
- free(pcx_image);
-
- return pcx_nomem;
- }
-
- setbuf(fp,fbuf);
-
- /* Going row by row, read the data from the file */
-
- dest = pcx_image;
- theight = height;
-
- while (theight--)
- {
- if (!pcx_decode_line(fp,dest,head.bytesperline))
- goto file_error;
-
- dest += width;
- }
-
- /* Now read in the palette */
-
- fseek(fp,-768,SEEK_END);
-
- fread(pal,sizeof(struct VgaPalette),256,fp);
-
- /* If an error occured, cleanup all buffers and return with an error */
-
- if (ferror(fp))
- {
- file_error:
- ErrorCode = -5;
- fclose(fp);
- FREE_BLOCK(fbuf);
- free(pcx_image);
- return pcx_ferror;
- }
-
- /* Free up routine buffers, and setup pix's data */
-
- fclose(fp);
- FREE_BLOCK(fbuf);
-
- pix->image = pcx_image;
- pix->width = width;
- pix->height = height;
-
- /* Last but not least, set the palette to the VGA's format */
- /* It's accomplished by simply shifting each RGB byte to the right twice */
-
- theight = 768;
- tpal = (byte *)pal;
-
- while (theight--)
- *tpal++ >>= 2;
-
- /* Everythings A-OK! */
-
- return pcx_ok;
- }
-
-